/**
 * @file XYXKC
 * @brief XYXKC's ESPONE Mind+ library.
 * @n This is the MIND+expansion module of the Xiaoyingxing patrol car.
 *
 * @copyright    XYXKC,2023
 * @copyright    MIT Lesser General Public License
 *
 * @author [email](hyc@xyxedu.cn)
 * @date  2023-10-25
 */
enum Motor {
    //% block="M1"
    M1,
    //% block="M2"
    M2,
    //% block="M3"
    M3,
    //% block="M4"
    M4,
}
enum ABOUT{
    //% block="leftMotor"
    Left,
    //% block="rightMotor"
    Right,
}
enum DIRECTION{
    //% block="forwardRotation"
    just,
    //% block="reversal"
    back,
}
enum directionOfTravel{
    //% block="advance"
    trolleyForward,
    //% block="backward"
    trolleyBackward,
    //% block="turnLeft"
    carTurningLeft,
    //% block="turnRight"
    carTurningRight,
}
enum LINEFOLLOWSENSORSNUM {
    //% blockId="LFS_1" block="①"
    0,
    //% blockId="LFS_2" block="②"
    1,
    //% blockId="LFS_3" block="③"
    2,
    //% blockId="LFS_4" block="④"
    3,
    //% blockId="LFS_5" block="⑤"
    4,

}
enum PATROLSTATUS {
    //% block="crossroads"
    patrolToTheIntersectionAndStop,
    //% block="leftIntersection"
    patrolToTheLeftIntersectionAndStop,
    //% block="rightIntersection"
    patrolToTheRightIntersectionAndStop,
    //% block="whenWireless"
    stopWhenPatrollingToWireless,
    //% block="centerOffline"
    patrolToCenterOffline,


}
enum TURNINGTOTHELINE{
    //% block="turnLeft"
    turnLeftToTheLine,
    //% block="turnRight"
    turnRightToTheLine,
}
//% color="#00bfff" iconWidth=50 iconHeight=40
namespace XYXKCMotor {
    //% block="initializeTheLeftMotorOfThePatrolCar[LETF]rightMotor[RIGHT]" blockType="command"
    //% LETF.shadow="dropdown" LETF.options="Motor" LETF.defl="Motor.M1"
    //% RIGHT.shadow="dropdown" RIGHT.options="Motor" RIGHT.defl="Motor.M2"
    export function MotorInit(parameter: any, block: any) {
        let letf = parameter.LETF.code;
        let right = parameter.RIGHT.code;
        Generator.addInclude('XYXKC_Motor','#include <XYXKC_CAR.h>')
        if(Generator.board === 'firebeetleesp32e'){//如果是arduinouno板，生成如下代码
            Generator.addObject('motor_ib','XYXKC_CAR','motor_ib(true)')
        }else if(Generator.board === 'esp32'){//如果是掌控板，生成如下代码
            Generator.addObject('motor_ib','XYXKC_CAR','motor_ib(false)');
        }
        Generator.addSetup('XYXKC_Motor_init',`motor_ib.motor_init(${'motor_ib.' + letf}, ${'motor_ib.' + right});`)
    }

    //% block="linePatrolCar[ABOUT]with[SPEED]%speedOf[DIRECTION]" blockType="command"
    //% ABOUT.shadow="dropdown" ABOUT.options="ABOUT" ABOUT.defl="ABOUT.Left"
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=35
    //% DIRECTION.shadow="dropdown" DIRECTION.options="DIRECTION" DIRECTION.defl="DIRECTION.just"
    export function MotorRun(parameter: any, block: any) {
        let about = parameter.ABOUT.code;
        let direction = parameter.DIRECTION.code;
        let speed = parameter.SPEED.code;
        Generator.addCode(`motor_ib.motorRun(${'motor_ib.' + about}, ${'motor_ib.' + direction},${speed});`)
    }
    //% block="patrolTrolley[SPEED]%speedOf[directionOfTravel]" blockType="command"
    //% directionOfTravel.shadow="dropdown" directionOfTravel.options="directionOfTravel" directionOfTravel.defl="directionOfTravel.trolleyForward"
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=28
    export function travelingOfPatrolCar(parameter: any, block: any) {
        let speed = parameter.SPEED.code;
        let direction = parameter.directionOfTravel.code;
        Generator.addCode(`${'motor_ib.'+ direction}(${speed});`)
    }
    //% block="patrolTrolley[SPEED]%speedOf[directionOfTravel] [TIME]second" blockType="command"
    //% directionOfTravel.shadow="dropdown" directionOfTravel.options="directionOfTravel" directionOfTravel.defl="directionOfTravel.trolleyForward"
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=28
    //% TIME.shadow="number" TIME.defl=1

    export function travelingOfPatrolCarTime(parameter: any, block: any) {
        let speed = parameter.SPEED.code;
        let direction = parameter.directionOfTravel.code;
        let time = parameter.TIME.code;
        Generator.addCode(`${'motor_ib.'+ direction}(${speed});`)
        Generator.addCode(`delay(${time}*1000);`)
        Generator.addCode(`motor_ib.stopOfPatrolCar();`)
    }

    //% block="thePatrolCarStopsMoving" blockType="command"
    export function stopOfPatrolCar(parameter: any, block: any) {

        Generator.addCode(`motor_ib.stopOfPatrolCar();`)
    }
    //% block="readLinePatrolSensor[LFS_NUM]statusOf" blockType="boolean"
    //% LFS_NUM.shadow="dropdown" LFS_NUM.options="LINEFOLLOWSENSORSNUM" LFS_NUM.defl="LINEFOLLOWSENSORSNUM.0"
    export function readLineFollowSensorsI2C(parameter: any, block: any) {

        let lfs_num = parameter.LFS_NUM.code
        Generator.addCode(`motor_ib.yfLS.readSensor(${lfs_num})`);
    }

    //% block="patrolTrolley[SPEED]%speedOf[PROPORTION]%adjustTheProportionOfLinePatrolTo[PATROLSTATUS]stop" blockType="command"
    //% PATROLSTATUS.shadow="dropdown" PATROLSTATUS.options="PATROLSTATUS" PATROLSTATUS.defl="PATROLSTATUS.patrolToTheIntersectionAndStop"
    //% PROPORTION.shadow="range" PROPORTION.params.min=0 PROPORTION.params.max=200 PROPORTION.defl=20
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=28
    export function linePatrolMethod(parameter: any, block: any) {

        let speed = parameter.SPEED.code
        let proportion = parameter.PROPORTION.code
        let linePatrolMethod = parameter.PATROLSTATUS.code
        Generator.addCode(`${'motor_ib.'+ linePatrolMethod}(${speed},float(${proportion})/100,float(${proportion})/100);`)
    }
    //% block="patrolTrolley[SPEED]%speedOf[PROPORTION]%adjustingTheProportionOfLinePatrolInspection[TIME]second" blockType="command"
    //% TIME.shadow="number" TIME.defl="1"
    //% PROPORTION.shadow="range" PROPORTION.params.min=0 PROPORTION.params.max=200 PROPORTION.defl=20
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=28
    export function linePatrolTimeStop(parameter: any, block: any) {

        let speed = parameter.SPEED.code
        let proportion = parameter.PROPORTION.code
        let time = parameter.TIME.code
        Generator.addCode(`motor_ib.linePatrolTimeStop(${speed},float(${proportion})/100,float(${proportion})/100,${time}*1000);`)
    }
    //% block="patrolTrolley[SPEED]%speedOf[PROPORTION1]%adjustmentRatio1Within[PROPORTION2]%adjustmentRatio2ExternalPatrolTo[PATROLSTATUS]stop" blockType="command"
    //% PATROLSTATUS.shadow="dropdown" PATROLSTATUS.options="PATROLSTATUS" PATROLSTATUS.defl="PATROLSTATUS.patrolToTheIntersectionAndStop"
    //% PROPORTION1.shadow="range" PROPORTION1.params.min=0 PROPORTION1.params.max=200 PROPORTION1.defl=20
    //% PROPORTION2.shadow="range" PROPORTION2.params.min=0 PROPORTION2.params.max=200 PROPORTION2.defl=20
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=28
    export function linePatrolMethod2(parameter: any, block: any) {

        let speed = parameter.SPEED.code
        let proportion1 = parameter.PROPORTION1.code
        let proportion2 = parameter.PROPORTION2.code
        let linePatrolMethod = parameter.PATROLSTATUS.code
        Generator.addCode(`${'motor_ib.'+ linePatrolMethod}(${speed},float(${proportion1})/100,float(${proportion2})/100);`)
    }
    //% block="patrolTrolley[SPEED]%speedOf[PROPORTION1]%adjustmentRatio1Within[PROPORTION2]%adjustmentRatio2ExternalLineInspection[TIME]second" blockType="command"
    //% TIME.shadow="number" TIME.defl="1"
    //% PROPORTION1.shadow="range" PROPORTION1.params.min=0 PROPORTION1.params.max=200 PROPORTION1.defl=20
    //% PROPORTION2.shadow="range" PROPORTION2.params.min=0 PROPORTION2.params.max=200 PROPORTION2.defl=20
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=28
    export function linePatrolTimeStop2(parameter: any, block: any) {

        let speed = parameter.SPEED.code
        let proportion1 = parameter.PROPORTION1.code
        let proportion2 = parameter.PROPORTION2.code
        let time = parameter.TIME.code
        Generator.addCode(`motor_ib.linePatrolTimeStop(${speed},float(${proportion1})/100,float(${proportion2})/100,${time}*1000);`)
    }

    //% block="patrolTrolley[SPEED]%speedOf[TURNINGTOTHELINE]toLinePatrolSensor[LFS_NUM]identifyLine" blockType="command"
    //% TURNINGTOTHELINE.shadow="dropdown" TURNINGTOTHELINE.options="TURNINGTOTHELINE" TURNINGTOTHELINE.defl="TURNINGTOTHELINE.turnLeftToTheLine"
    //% SPEED.shadow="range" SPEED.params.min=0 SPEED.params.max=100 SPEED.defl=35
    //% LFS_NUM.shadow="dropdown" LFS_NUM.options="LINEFOLLOWSENSORSNUM" LFS_NUM.defl="LINEFOLLOWSENSORSNUM.2"
    export function turningToTheLine(parameter: any, block: any) {

        let speed = parameter.SPEED.code
        let turning = parameter.TURNINGTOTHELINE.code
        let lfs = parameter.LFS_NUM.code
        Generator.addCode(`${'motor_ib.'+ turning}(${speed},${lfs});`)
    }
    //% block="speechRecognitionAndReturningData " blockType="reporter"
    export function vcSpeechRecognitionSoftware(parameter: any, block: any) {
        Generator.addSetup(`vc_initSetup`, `Serial1.begin(9600,33, -1);`);
        Generator.addObject(`defineserialReceiveDataFun`,'uint8_t' ,``+
            `serialReceiveData() {\n`+
            `  uint8_t c;\n`+
            `  static uint8_t inBuf[3];   //数据数组\n`+         // static 必须有，在测试ESPONE 主板时，没有无法正常工作
            `  static uint8_t offset;\n`+
            `  static uint32_t checksum;\n`+
            `  static enum _serial_state { IDLE, HEADER_5A } c_state;\n\n`+
            `  while (Serial1.available()) {\n`+
            `    c = Serial1.read();     // 读串口缓冲区\n`+
            `    if (c_state == IDLE) {        // 串口状态空闲,等待 HEADER 5A 状态的到来\n`+
            `      if (c == 0x5A) {            // 判断是否进入 HEADER 5A\n`+
            `        checksum = c;             // 校验和 1  -  head\n`+
            `        c_state = HEADER_5A;      // 进入 HEADER_5A 状态\n`+
            `        offset = 0;\n`+
            `      } else  c_state = IDLE;     // 返回IDLE状态\n`+
            `    } else if (c_state == HEADER_5A && offset < 3) {\n`+
            `      checksum += c;              // 校验和 2  -  data\n`+
            `      inBuf[offset] = c;\n`+
            `      offset++;\n`+
            `    } else if (c_state == HEADER_5A && offset >= 3) {\n`+
            `      c_state = IDLE;             // 返回IDLE状态\n`+
            `      if ((checksum & 0xFF) == c) {\n`+
            `        return inBuf[0];          // 返回指令值\n`+
            `      }\n`+
            `    }\n`+
            `  }\n`+
            `  return 0x01;                    // 未接收数据，默认返回0x01\n`+
            `}`
        );

        Generator.addCode('serialReceiveData()');
    }

}
